import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import matplotlib.pylab as plt


#导入cifar10数据集
(train_images,train_labels),(test_images,test_labels)=keras.datasets.cifar10.load_data()

# #探索数据
# #查看训练集图片形状 >>(50000, 32, 32, 3)
# print(train_images.shape)
# #查看训练集标签数量 >>50000
# print(len(train_labels))
# #打印训练集标签
# print(train_labels)
# #查看测试集图片形状 >>(10000, 32, 32, 3)
# print(test_images.shape)
# #查看测试集标签数量>>10000
# print(len(test_labels))

#对数据进行归一化处理
train_images = train_images.astype('float32')/255.0
test_images = test_images.astype('float32')/255.0
train_labels = keras.utils.to_categorical(train_labels,10)
test_labels = keras.utils.to_categorical(test_labels,10)

#使用Cifar10创建一个ResNet模型
inputs = keras.Input(shape=(32,32,3),name='image')
x = layers.Conv2D(32,3,activation='relu')(inputs)
x = layers.Conv2D(64,3,activation='relu')(x)
block_1_output = layers.MaxPooling2D(3)(x)

x = layers.Conv2D(64, 3, activation="relu", padding="same")(block_1_output)
x = layers.Conv2D(64, 3, activation="relu", padding="same")(x)
block_2_output = layers.add([x, block_1_output])

x = layers.Conv2D(64, 3, activation="relu", padding="same")(block_2_output)
x = layers.Conv2D(64, 3, activation="relu", padding="same")(x)
block_3_output = layers.add([x, block_2_output])

x = layers.Conv2D(64, 3, activation="relu")(block_3_output)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(256, activation="relu")(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(10)(x)

model = keras.Model(inputs, outputs, name="resnet_cifar10")
model.summary()

# 绘制模型可视化结构图（等到第二章用tensorboard来做）
# keras.utils.plot_model(model, "mini_resnet.png", show_shapes=True)

#保存模型图片,命名为resnet-cifar.png（等到第二章用tensorboard来做）
# keras.utils.plot_model(model,'resnet-cifar.png')

#保存模型，模型名字为resnet_model
model.save('resnet_model')

#使用resnet_model模型对cifar10数据集进行训练
model.compile(
    loss=keras.losses.CategoricalCrossentropy(from_logits=True),
    optimizer=keras.optimizers.RMSprop(1e-3),
    metrics=['accuracy'],
)

# 将数据集限制在前1000个样本中，限制时间
history = model.fit(train_images[:20000],train_labels[:20000],batch_size=64,epochs=16,validation_split=0.2)
# 2000张图片，epochs=5,batch_size=64 >> 5s 3ms/sample - loss: 2.0630 - acc: 0.2100 - val_loss: 2.0155 - val_acc: 0.1950
# 10000张图片，epochs=5,batch_size=64 >> 26s 3ms/sample - loss: 1.6540 - acc: 0.3776 - val_loss: 1.6095 - val_acc: 0.3855
# 20000张图片，epochs=7,batch_size=128 >> 50s 3ms/sample - loss: 1.4495 - acc: 0.4753 - val_loss: 1.3737 - val_acc: 0.4975
# 20000张图片，epochs=7,batch_size=64 >> 53s 3ms/sample - loss: 1.2243 - acc: 0.5591 - val_loss: 1.1600 - val_acc: 0.5720
# 20000张图片，epochs=16,batch_size=64 >> 60s 4ms/sample - loss: 0.7374 - accuracy: 0.7374 - val_loss: 0.9828 - val_accuracy: 0.6672

#绘制模型的准确率以及损失曲线
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss =history.history['val_loss']

plt.figure(figsize=(8, 8))
plt.subplot(2, 1, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.ylabel('Accuracy')
plt.ylim([min(plt.ylim()),1])
plt.title('Training and Validation Accuracy')

plt.subplot(2, 1, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.ylabel('Cross Entropy')
# plt.title([0, 1.0]) 这行代码是啥意思？
plt.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.show()

